package com.huanmeiqi.demo.persistence.two;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @author cq.Wang
 * @date 2018/6/14 10:12
 * @description
 */
@Configuration // 该注解类似于spring配置文件
@MapperScan(basePackages = "com.huanmeiqi.demo.persistence.two.mapper")
public class MyBatisCfg {

    @Autowired
    private Environment env;

    @Bean
    @Qualifier("readDataSource")
    public DataSource readDataSource() throws Exception {
        Properties props = new Properties();
        props.put("driverClassName", env.getProperty("read.jdbc.driverClassName"));
        props.put("url", env.getProperty("read.jdbc.url"));
        props.put("username", env.getProperty("read.jdbc.username"));
        props.put("password", env.getProperty("read.jdbc.password"));
        // 此外props中也可以设置一些maxActive、maxIdle等配置来更好的整合Druid
        return DruidDataSourceFactory.createDataSource(props);
    }

    //    public DynamicDataSource
    @Bean
    @Qualifier("writeDataSource")
    public DataSource writeDataSource() throws Exception {
        Properties props = new Properties();
        props.put("driverClassName", env.getProperty("write.jdbc.driverClassName"));
        props.put("url", env.getProperty("write.jdbc.url"));
        props.put("username", env.getProperty("write.jdbc.username"));
        props.put("password", env.getProperty("write.jdbc.password"));
        return DruidDataSourceFactory.createDataSource(props);
    }

    /**
     * @Primary 该注解表示在同一个接口有多个实现类可以注入的时候，默认选择哪一个，而不是让@autowire注解报错
     * @Qualifier 根据名称进行注入，通常是在具有相同的多个类型的实例的一个注入（例如有多个DataSource类型的实例）
     */
    @Bean
    @Primary
    public DynamicDataSource dataSource() throws Exception {
        Map<Object, Object> targetDataSources = new HashMap<>();
        DataSource readDataSource = readDataSource();
        DataSource writeDataSource = writeDataSource();
        targetDataSources.put(DatabaseType.READ_DB, readDataSource);
        targetDataSources.put(DatabaseType.WRITE_DB, writeDataSource);

        // 设置动态数据源有哪些数据源以及默认的数据源
        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法
        dataSource.setDefaultTargetDataSource(readDataSource);// 默认的datasource设置为READ_DB

        return dataSource;
    }

    /**
     * 根据数据源创建SqlSessionFactory
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
        fb.setDataSource(dataSource());// 指定数据源(这个必须有，否则报错)
        // 下边两句仅仅用于*.xml文件，如果整个持久层操作不需要使用到xml文件的话（只用注解写SQL就可以搞定），则不加
        fb.setTypeAliasesPackage(env.getProperty("mybatis.typeAliasesPackage"));// 指定domain基包
        fb.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(env.getProperty("mybatis.mapperLocations")));//指定xml映射文件位置
        return fb.getObject();
    }

    /**
     * 配置事务管理器
     */
    @Bean
    public DataSourceTransactionManager transactionManager() throws Exception {
        return new DataSourceTransactionManager(dataSource());
    }
}
